package com.huimingpay.transaction.service;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.huimingpay.common.cache.Cache;
import com.huimingpay.common.domain.BusinessException;
import com.huimingpay.common.domain.CommonErrorCode;
import com.huimingpay.common.util.RedisUtil;
import com.huimingpay.common.util.StringUtil;
import com.huimingpay.transaction.api.PayChannelService;
import com.huimingpay.transaction.convert.PayChannelParamConvert;
import com.huimingpay.transaction.convert.PlatformChannelConvert;
import com.huimingpay.transaction.dto.PayChannelDTO;
import com.huimingpay.transaction.dto.PayChannelParamDTO;
import com.huimingpay.transaction.dto.PlatformChannelDTO;
import com.huimingpay.transaction.entity.AppPlatformChannel;
import com.huimingpay.transaction.entity.PayChannelParam;
import com.huimingpay.transaction.entity.PlatformChannel;
import com.huimingpay.transaction.mapper.AppPlatformChannelMapper;
import com.huimingpay.transaction.mapper.PayChannelMapper;
import com.huimingpay.transaction.mapper.PayChannelParamMapper;
import com.huimingpay.transaction.mapper.PlatformChannelMapper;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;

/**
 * ClassName:PayChannelServiceImpl
 * Package:com.huimingpay.transaction.service
 * Time: 2024/7/23
 */

@Service // 声明为dubbo服务
public class PayChannelServiceImpl implements PayChannelService {
    @Resource
    PlatformChannelMapper platformChannelMapper;

    @Resource
    AppPlatformChannelMapper appPlatformChannelMapper;

    @Resource
    PayChannelMapper payChannelMapper;

    @Resource
    PayChannelParamMapper payChannelParamMapper;

    @Resource
    Cache cache;

    /**
     * 获取平台服务类型
     *
     * @return 平台服务类型列表
     * @throws BusinessException
     */
    @Override
    public List<PlatformChannelDTO> queryPlatformChannel() throws BusinessException {
        // 从数据库中查询平台服务列表
        List<PlatformChannel> platformChannelList = platformChannelMapper.selectList(null);

        // 将平台服务实体列表转换为数据传输对象列表
        List<PlatformChannelDTO> platformChannelDTOS = PlatformChannelConvert.INSTANCE.listentity2listdto(platformChannelList);

        // 返回平台服务数据传输对象列表
        return platformChannelDTOS;
    }

    /**
     * 为app绑定指定的服务类型
     *
     * @param appId                应用id
     * @param platformChannelCodes 平台服务类型列表
     * @throws BusinessException
     */
    @Override
    @Transactional
    public void bindPlatformChannelForApp(String appId, String platformChannelCodes) throws BusinessException {
        //根据应用id和服务类型code查询 ，如果已经绑定则不再插入，否则插入记录
        AppPlatformChannel platformChannel = appPlatformChannelMapper.selectOne(new LambdaQueryWrapper<AppPlatformChannel>()
                .eq(AppPlatformChannel::getAppId, appId)
                .eq(AppPlatformChannel::getPlatformChannel, platformChannelCodes));
        if (platformChannel == null) {
            // 创建平台服务与应用绑定实体
            AppPlatformChannel appPlatformChannel = new AppPlatformChannel();
            appPlatformChannel.setAppId(appId);
            appPlatformChannel.setPlatformChannel(platformChannelCodes);
            // 保存平台服务与应用绑定实体
            appPlatformChannelMapper.insert(appPlatformChannel);
        } else {
            throw new BusinessException(CommonErrorCode.E_300111); // 平台服务已经绑定
        }
    }

    /**
     * 应用是否已经绑定了某个服务类型
     *
     * @param appId           应用id
     * @param platformChannel 平台服务类型
     * @return 已绑定返回1，否则 返回0
     */
    @Override
    public int queryAppBindPlatformChannel(String appId, String platformChannel) throws BusinessException {
        // 创建一个LambdaQueryWrapper对象用于构造查询条件
        LambdaQueryWrapper<AppPlatformChannel> queryWrapper = new LambdaQueryWrapper<AppPlatformChannel>()
                // 添加查询条件：应用id等于传入的appId
                .eq(AppPlatformChannel::getAppId, appId)
                // 添加查询条件：平台服务类型等于传入的platformChannel
                .eq(AppPlatformChannel::getPlatformChannel, platformChannel);

        // 执行查询，获取匹配记录的数量
        Integer selectCount = appPlatformChannelMapper.selectCount(queryWrapper);

        // 判断匹配记录的数量是否大于0，若大于0则返回1，否则返回0
        return selectCount > 0 ? 1 : 0;
    }

    /**
     * 根据服务类型的code获取对应的支付渠道
     *
     * @param platformChannelCode 平台服务类型code
     * @return 支付渠道列表
     * @throws BusinessException
     */
    @Override
    public List<PayChannelDTO> queryPayChannelByPlatformChannel(String platformChannelCode) throws BusinessException {
        return payChannelMapper.selectPayChannelByPlatformChannel(platformChannelCode);
    }

    /**
     * 保存支付渠道参数
     *
     * @param payChannelParam 支付渠道参数
     * @throws BusinessException
     */
    @Override
    public void savePayChannelParam(PayChannelParamDTO payChannelParam) throws BusinessException {
        //校验传入的参数是否为空
        if (payChannelParam == null
                || StringUtil.isBlank(payChannelParam.getPayChannel())
                || StringUtil.isBlank(payChannelParam.getPlatformChannelCode())
                || StringUtil.isBlank(payChannelParam.getAppId())
                || payChannelParam.getMerchantId() == null
                || StringUtil.isBlank(payChannelParam.getChannelName())) {
            throw new BusinessException(CommonErrorCode.E_300009); // 参数为空
        }
        // 校验应用是否绑定服务类型
        Long idByAppPlatformChannel = selectIdByAppPlatformChannel(payChannelParam.getAppId(), payChannelParam.getPlatformChannelCode());
        if (idByAppPlatformChannel == null) {
            throw new BusinessException(CommonErrorCode.E_300010); // 应用未绑定服务类型
        }
        //在数据表pay_channel_param中根据idByAppPlatformChannel和原始支付渠道编码PayChannel查询是否有配置记录
        //如果存在则更新，否则插入
        LambdaQueryWrapper<PayChannelParam> queryWrapper = new LambdaQueryWrapper<PayChannelParam>()
                .eq(PayChannelParam::getAppPlatformChannelId, idByAppPlatformChannel)
                .eq(PayChannelParam::getPayChannel, payChannelParam.getPayChannel());
        PayChannelParam payChannelParamEntity = payChannelParamMapper.selectOne(queryWrapper);
        if (payChannelParamEntity != null) {
            //更新 如果查询的配置存在，则商户Id、应用与支付渠道绑定ID、原始支付渠道编码都是有数据的
            //所以只需更新配置名称、支付参数即可
            payChannelParamEntity.setChannelName(payChannelParam.getChannelName());
            payChannelParamEntity.setParam(payChannelParam.getParam());
            payChannelParamMapper.updateById(payChannelParamEntity);
        } else {
            //插入
            PayChannelParam payChannelParam1 = PayChannelParamConvert.INSTANCE.dto2entity(payChannelParam);
            //此时应用与支付渠道绑定ID并没有设置
            payChannelParam1.setAppPlatformChannelId(idByAppPlatformChannel);
            // 设置主键id为Null,使之自动生成
            payChannelParam1.setId(null);
            //插入
            payChannelParamMapper.insert(payChannelParam1);
        }

        //更新缓存
        updateCache(payChannelParam.getAppId(), payChannelParam.getPlatformChannelCode());
    }

    /**
     * 更新Redis缓存
     *
     * @param appId               平台应用id
     * @param platformChannelCode 平台服务类型编码code
     */
    private void updateCache(String appId, String platformChannelCode) {
        //1、构建key 如：HM_PAY_PARAM:b910da455bc84514b324656e1088320b:huimin_c2b
        String keyBuilder = RedisUtil.keyBuilder(appId, platformChannelCode);
        //2、根据key查询缓存中是否存在该key
        if (cache.exists(keyBuilder)) {
            //存在则删除缓存
            cache.del(keyBuilder);
        }
        //3、如果存在则删除原有缓存，再重新设置新的缓存，以下方法中已写入设置新缓存的功能
        queryPayChannelParamsByAppAndPlatformChannel(appId, platformChannelCode);
    }

    /**
     * 根据应用和服务类型查询支付渠道参数列表 结果可能是多个(支付宝渠道参数 微信渠道参数)
     *
     * @param appId               平台应用id
     * @param platformChannelCode 平台服务类型编码code
     * @return 支付渠道参数列表
     * @throws BusinessException
     */
    @Override
    public List<PayChannelParamDTO> queryPayChannelParamsByAppAndPlatformChannel(String appId, String platformChannelCode) throws BusinessException {
        //先从redis查询，如果有则返回
        String redisKey = RedisUtil.keyBuilder(appId, platformChannelCode);
        if (cache.exists(redisKey)) {
            // 获取缓存中的支付渠道参数列表
            String s = cache.get(redisKey);
            // 反序列化
            List<PayChannelParamDTO> payChannelParamDTOS = JSON.parseArray(s, PayChannelParamDTO.class);
            // 返回结果
            return payChannelParamDTOS;
        }

        //缓存中没有 则从数据库查询 并将查询结果写入缓存
        // 根据应用id和平台服务类型code查询应用和服务类型绑定的id
        Long idByAppPlatformChannel = selectIdByAppPlatformChannel(appId, platformChannelCode);

        // 构造查询条件
        LambdaQueryWrapper<PayChannelParam> queryWrapper = new LambdaQueryWrapper<PayChannelParam>()
                .eq(PayChannelParam::getAppPlatformChannelId, idByAppPlatformChannel);

        // 执行查询获取支付渠道参数列表
        List<PayChannelParam> payChannelParams = payChannelParamMapper.selectList(queryWrapper);

        //entity转dto,再写入缓存
        List<PayChannelParamDTO> payChannelParamDTOS = PayChannelParamConvert.INSTANCE.listentity2listdto(payChannelParams);

        cache.set(redisKey, JSON.toJSONString(payChannelParamDTOS));
        // 返回结果
        return payChannelParamDTOS;
    }


    /**
     * 根据应用、服务类型及支付渠道获取原始支付参数param，结果只能是一个
     *
     * @param appId               平台应用id
     * @param platformChannelCode 平台服务类型编码code
     * @param payChannel          原始支付渠道编码code
     * @return 支付渠道参数
     * @throws BusinessException
     */
    @Override
    public PayChannelParamDTO queryPayChannelParamByAppAndPlatformAndPayChannel(String appId, String platformChannelCode, String payChannel) throws BusinessException {
        // 根据应用id和服务类型code查询支付渠道参数列表
        List<PayChannelParamDTO> payChannelParamDTOS = queryPayChannelParamsByAppAndPlatformChannel(appId, platformChannelCode);

        // 遍历支付渠道参数列表
        for (PayChannelParamDTO payChannelParamDTO : payChannelParamDTOS) {
            // 判断当前支付渠道参数的支付渠道编码是否与传入的支付渠道编码相等
            if (payChannelParamDTO.getPayChannel().equals(payChannel)) {
                // 若相等，则返回当前支付渠道参数
                return payChannelParamDTO;
            }
        }

        // 若遍历完所有支付渠道参数后仍未找到匹配的支付渠道参数，则返回null
        return null;
    }


    /**
     * 根据应用Id和平台服务类型code查询 应用和服务类型绑定的id
     *
     * @param appId               应用Id
     * @param platformChannelCode 平台服务类型code
     * @return 平台服务与应用绑定的id
     */
    private Long selectIdByAppPlatformChannel(String appId, String platformChannelCode) {
        // 创建一个LambdaQueryWrapper对象，用于构建查询条件
        LambdaQueryWrapper<AppPlatformChannel> queryWrapper = new LambdaQueryWrapper<AppPlatformChannel>()
                // 添加查询条件：AppPlatformChannel表中的appId字段等于传入的appId
                .eq(AppPlatformChannel::getAppId, appId)
                // 添加查询条件：AppPlatformChannel表中的platformChannel字段等于传入的platformChannelCode
                .eq(AppPlatformChannel::getPlatformChannel, platformChannelCode);

        // 使用appPlatformChannelMapper的selectOne方法执行查询，返回符合条件的AppPlatformChannel对象
        AppPlatformChannel appPlatformChannel = appPlatformChannelMapper.selectOne(queryWrapper);

        // 如果查询结果不为空，则返回该对象的id字段值；否则返回null
        return appPlatformChannel != null ? appPlatformChannel.getId() : null;
    }

}
